﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WarehouseManagement.BusinessLogic.DTO;
using WarehouseManagement.DataAccess;

namespace WarehouseManagement.BusinessLogic.BC
{
    public class StockBC : BaseBC
    {

        public MerchandiseInStock GetMerchandiseInStockCurrentTime(int merchandiseId, DateTime from)
        {
            return GetMerchandiseInStock(merchandiseId, from.Month, from.Year);
        }

        //private DateTime EnsureFromDate(int merchandiseId, int month, int year)
        //{
        //    var fromDate = new DateTime(year, month, 1);

        //    if (!Context.MerchandiseInStocks.Any(e => (e.Month == month && e.Year == year) && e.MerchandiseId == merchandiseId))
        //    {
        //        var l = Context.MerchandiseInStocks.Where(e => e.MerchandiseId == merchandiseId
        //            && new DateTime(e.Year, e.Month, 1).Date <= fromDate.Date);
        //        if (l.Count() > 0)
        //        {
        //            var latest = l.OrderByDescending(e => new DateTime(e.Year, e.Month, 1)).FirstOrDefault();
        //            if (latest != null)
        //                fromDate = new DateTime(latest.Year, latest.Month, 1);
        //        }
        //    }
        //    return fromDate;
        //}
        public MerchandiseInStock GetMerchandiseInStock(int merchandiseId, int month, int year)
        {
            MerchandiseInStock result = new MerchandiseInStock();

            //var fromDate = EnsureFromDate(merchandiseId, month, year);
            var fromDate = new DateTime(year, month, 1);
            var list = Context.MerchandiseInStocks
                .Where(e => e.MerchandiseId == merchandiseId)
                .Select(e =>
                new
                {
                    e.MerchandiseId,
                    FromDate = new DateTime(e.Year, e.Month, 1),
                    e.QuantityInStock,
                    e.ValueInStock
                });

            var list2 = list.Where(e => e.FromDate <= fromDate)
                .OrderByDescending(e => e.FromDate)
                .ToList();

            if (list2.Count() > 0)
            {
                var firstItem = list2.FirstOrDefault();
                if (firstItem != null)
                {
                    result = new MerchandiseInStock()
                    {
                        MerchandiseId = firstItem.MerchandiseId,
                        Month = month,
                        Year = year,
                        QuantityInStock = firstItem.QuantityInStock,
                        ValueInStock = firstItem.ValueInStock
                    };
                }
            }

            return result;
        }

        public MerchandiseInStock GetTonDauKy(int merchandiseId, DateTime date)
        {

            var _importBC = new ImportBC();
            var _exportBC = new ExportBC();
            try
            {
                var lastMonth = new DateTime(date.Year, date.Month, 1);
                var qtyLastPeriod = GetMerchandiseInStock(merchandiseId, lastMonth.Month, lastMonth.Year);

                var fromDate = new DateTime(date.Year, date.Month, 1);
                var toDate = date.Date.AddDays(-1);

                var importInfo = _importBC.GetImportInformationOptimized(merchandiseId, fromDate.Date, toDate.Date);
                var exportInfo = _exportBC.GetExportInformationOptimized(merchandiseId, fromDate.Date, toDate.Date);

                var slTonDauKy = (decimal)qtyLastPeriod.QuantityInStock + (decimal)(importInfo.TotalImportQuantity - exportInfo.TotalExportQuantity);
                var gtTonDauKy = (decimal)qtyLastPeriod.ValueInStock + (decimal)(importInfo.TotalImportValue - exportInfo.TotalExportOriginValue);
                return new MerchandiseInStock() { MerchandiseId = merchandiseId, QuantityInStock = (double)slTonDauKy, ValueInStock = (decimal)gtTonDauKy };
            }
            finally
            {
                _importBC = null;
                _exportBC = null;
            }
        }

        public void AppendMerchandiseInStock(int merchandiseId, int month, int year, double quantity, decimal value)
        {

            //var previousItem = GetMerchandiseInStock(merchandiseId, month, year);

            if (Context.MerchandiseInStocks.Any(e =>
                (e.Month == month && e.Year == year)
                && e.MerchandiseId == merchandiseId))
            {

                var entity = Context.MerchandiseInStocks.SingleOrDefault(e =>
                     (e.Month == month && e.Year == year)
                    && e.MerchandiseId == merchandiseId);
                entity.QuantityInStock = quantity;
                entity.ValueInStock = value;
            }
            else
            {
                Context.MerchandiseInStocks.InsertOnSubmit(new MerchandiseInStock()
                {
                    Id = Guid.NewGuid(),
                    Month = month,
                    Year = year,
                    MerchandiseId = merchandiseId,
                    ValueInStock = value,
                    QuantityInStock = quantity
                });
            }
            SubmitChanges();
        }

        public void UpdateAllMerchandisesInStockAfterDate(int merchandiseId, int month, int year)
        {
            var fromDate = new DateTime(year, month, 1);
            var list = Context.MerchandiseInStocks.AsEnumerable()
                .Where(e =>
                    new DateTime(e.Year, e.Month, 1) > fromDate.Date
                    && e.MerchandiseId == merchandiseId);

            foreach (var item in list)
            {
                //var obj = GetTonDauKy(merchandiseId, new DateTime(item.Year, item.Month, 1));

                var fd = new DateTime(item.Year, item.Month, 1).AddMonths(-1);
                var td = new DateTime(fd.Year, fd.Month, DateTime.DaysInMonth(fd.Year, fd.Month));

                var tonCuoiKy = GetViewStockInfo(item.MerchandiseId, fd, td);


                AppendMerchandiseInStock(item.MerchandiseId, item.Month, item.Year, tonCuoiKy.EndPeriodQuantity, tonCuoiKy.EndPeriodValue);
            }
        }

        public ViewStockDTO GetViewStockInfo(int merchandiseId, DateTime from, DateTime to)
        {
            var importBC = new ImportBC();
            var exportBC = new ExportBC();

            try
            {

                var merchandise = Context.Merchandises.SingleOrDefault(e => e.Id == merchandiseId);
                var prePeriod = GetTonDauKy(merchandiseId, from);
                var importInfo = importBC.GetImportInformationOptimized(merchandiseId, from, to);
                var exportInfo = exportBC.GetExportInformationOptimized(merchandiseId, from, to);
                //var endPeriod = GetMerchandiseInStock(merchandiseId, to.Month, to.Year);

                var dto = new ViewStockDTO()
                {
                    CategoryName = merchandise.MerchandiseCategory != null ? merchandise.MerchandiseCategory.MerchandiseCategoryName : "",
                    MerchandiseName = merchandise.MerchandiseName,
                    Unit = merchandise.Unit,

                    PrePeriodQuantity = prePeriod.QuantityInStock,
                    PrePeriodValue = prePeriod.ValueInStock,

                    ImportQuantity = importInfo.TotalImportQuantity,
                    ImportValue = importInfo.TotalImportValue,

                    ExportQuantity = exportInfo.TotalExportQuantity,
                    ExportValue = exportInfo.TotalExportValue,
                    ExportOriginValue = exportInfo.TotalExportOriginValue

                };
                dto.EndPeriodQuantity = dto.PrePeriodQuantity + (dto.ImportQuantity - dto.ExportQuantity);
                dto.EndPeriodValue = dto.PrePeriodValue + (dto.ImportValue - dto.ExportOriginValue);
                return dto;
            }
            finally
            {
                importBC = null;
                exportBC = null;
            }
        }

        public IEnumerable<ViewStockDTO> GetViewStockInfo(DateTime from, DateTime to)
        {
            var merchandises = Context.Merchandises.AsEnumerable();
            foreach (var item in merchandises)
            {
                yield return GetViewStockInfo(item.Id, from, to);
            }
        }

        public void SaveMerchandiseInStockList(IEnumerable<InputMerchandiseInStockDTO> list)
        {
            int month = DateTime.Today.Month;
            int year = DateTime.Today.Year;
            try
            {
                this.BeginTransaction();
                foreach (var item in list)
                {
                    AppendMerchandiseInStock(item.MerchandiseId, month, year, item.Quantity, item.TotalUnitPrice);

                    var fd = new DateTime(year, month, 1);
                    var td = new DateTime(fd.Year, fd.Month, DateTime.DaysInMonth(fd.Year, fd.Month));

                    var tonCuoiKy = GetViewStockInfo(item.MerchandiseId, fd, td);
                    var nextMonth = fd.AddMonths(1);

                    AppendMerchandiseInStock(item.MerchandiseId, nextMonth.Month, nextMonth.Year, tonCuoiKy.EndPeriodQuantity, tonCuoiKy.EndPeriodValue);

                }
                this.CommitTransaction();
            }
            catch (Exception ex)
            {
                this.RollbackTransaction();
                throw ex;
            }
        }
    }
}
